
#ifdef LRSTAR

      #include "ComGlobal.h"
		#include "PGGlobal.h"

/*--- Variables. --------------------------------------------------*/

		char** PG::line_ptr;
		char*  PG::input_start;
		char*  PG::input_end;

		char   lexfid [MAX_PATH];

///////////////////////////////////////////////////////////////////////////////
//                                                                           //

int   PG::Main (int na, char** arg)
{
      if (Start (na, arg))
		{
			PGParser::initialize (optn[MAX_SYM]);
			if (PGParser::parse (input_start) > 0)
			{
				PrintGrammar();
				PrintHtml();
				if (CheckGrammar())
				{
					OutputLexicalSymbols();
					if (BuildLR1())  
					{
						if (ComputeLA())
						{
							if (OptimizeStates())
							{
								PrintStates();
								CreateTables();
								PG::Terminate (0);
								return 1;
							} 
						}
			      }
				}
			}
		}
		return 0;
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //

int   PG::Start (int na, char *arg []) /* Display program information. */
{
      int i, ne, filedesc, rc;
		char dn[256], fn[256], ft[256], string[64];

      time1 = clock();

		if (!inputi ("")) PG::Terminate (0);

		line_ptr     = ::line_ptr;
		input_start  = ::input_start;
		input_end    = ::input_end;

		for (i = 0; i < 159; i++) spaces [i] = ' ';

		memory_usage  = 0;
		memory_max    = 0;
      ne            = 0;
      n_warnings    = 0;
      n_errors      = 0;

		return 1;
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //

void  PG::OutputLexicalSymbols ()
{
		char* p;
      char  string[256];
      int   filedesc, first, i, k, n, ns, len;

		int* seq;
		ALLOC (seq, N_terms);
		SORTNAMES (term_name, N_terms, seq);
		 
      strcpy (lexfid, gdn);
      strcat (lexfid, gfn);
      strcat (lexfid, ".lex");

      if (chmod (lexfid, S_IWRITE) == 0) // File can be written ?
      {
         if (unlink (lexfid) != 0) // Delete it?
         {
	         if (++n_errors == 1) prt_log ("\n");
				prt_log ("Output file '%s' cannot be written!\n", lexfid);
            PG::Terminate (1);
         }
      }

		filedesc = open (lexfid, O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE);

	/* <lexical> symbols */

		len = sprintf (string, "\n/* %s lexical symbols, generated by LRSTAR. */\n\n", gfn);
		write (filedesc, string, len);
		 
		len = sprintf (string, "   \"tab=%d\"\n\n", optn[PG_TAB]);
		write (filedesc, string, len);

		n = 0;
		for (i = 0; i < N_terms; i++)
		{
			if (seq[i] == 0) continue; // Skip <error> symbol.
			if (seq[i] == eof_term && optn[PG_EOFINCLUDED] == 0) continue;
			if (term_name[seq[i]][0] == '<')
			{
 				n++;
				write (filedesc, "   ", 3);
				k = strlen(term_name[seq[i]]);
				write (filedesc, term_name[seq[i]], k);
				ns = (max_terml - k + 3);
				if (ns > 0) write (filedesc, spaces, ns);
				k = sprintf (string, "%5d", seq[i]);
				write (filedesc, string, k);
				write (filedesc, "\n", 1);
			}
		}
		if (n) first = 1;

	/* Keywords */

		n = 0;
		char quote = '\'';
		for (i = 0; i < N_terms; i++)
		{
			if (itsakeyword(term_name[seq[i]]))
			{
				n++;
				if (first)
				{
					first = 0;
					write (filedesc, "\n", 1);
				}
				write (filedesc, "   ", 3);
				p   = slash_inside_keyword (term_name[seq[i]], quote);
				len = strlen (p);
				write (filedesc, p, len);
				ns = (max_terml - len + 3);
				if (ns > 0) write (filedesc, spaces, ns);
				len = sprintf (string, "%5d", seq[i]);
				write (filedesc, string, len);
				write (filedesc, "\n", 1);
			}
		}
		if (n) first = 1;

	/* 'literal' symbols */

		for (i = 0; i < N_terms; i++)
		{
			if (term_name[seq[i]][0] == '{') continue;
			if (term_name[seq[i]][0] == '<') continue;
			if (itsakeyword (term_name[seq[i]])) continue;
			if (first)
			{
				first = 0;
				write (filedesc, "\n", 1);
			}
			write (filedesc, "   ", 3);
			p   = slash_inside (term_name[seq[i]]);
			len = strlen (p);
			write (filedesc, p, len);
			ns = (max_terml - len + 3);
			if (ns > 0) write (filedesc, spaces, ns);
			len = sprintf (string, "%5d", seq[i]);
			write (filedesc, string, len);
			write (filedesc, "\n", 1);
		}
		if (n) first = 1;

	/* {semantic} symbols (for debugging only) 

		for (i = 0; i < N_terms; i++)
		{
			if (term_name[seq[i]][0] != '{') continue;
			if (first)
			{
				first = 0;
				write (filedesc, "\n", 1);
			}
			write (filedesc, "   ", 3);
			k = strlen(term_name[seq[i]]);
			write (filedesc, term_name[seq[i]], k);
			ns = (max_terml - k + 3);
			if (ns > 0) write (filedesc, spaces, ns);
			len = sprintf (string, "%5d", seq[i]);
			write (filedesc, string, len);
			write (filedesc, "\n", 1);
		}	*/

		FREE (seq, N_terms);

		len = sprintf (string, "\n/* End of %s lexical symbols. */\n\n", gfn);
		write (filedesc, string, len);
		close (filedesc);

      chmod (lexfid, S_IREAD); // Make output file read-only.
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //

char* PG::slash_inside (char* term_name)
{
		static char string[128];
		char *p = term_name+1;
		char  c = 0;
		int   i = 1;
		do
		{
			if (*p != '\\')
			{
				string[i++] = *p++;
				if (i > 127)
				{
					n_errors++;
					if (n_errors == 1) prt_log ("\n");
					prt_log ("In file '%s', literal is longer than 128 characters.\n\n", grmfid);
					PG::Terminate (6);
				}
			}
			else
			{
				p++;
				if (*p == '\'')
				{
					if (c == 0) c = '\"';
					else if (c == '\'')
					{
						n_errors++;
						if (n_errors == 1) prt_log ("\n");
						prt_log ("In file '%s', literal contains both \' and \", cannot convert for use in lexical grammar.\n", grmfid);
						PG::Terminate (6);
					}
				}
				else if (*p == '\"')
				{
					if (c == 0) c = '\'';
					else if (c == '\"')
					{
						n_errors++;
						if (n_errors == 1) prt_log ("\n");
						prt_log ("In file '%s', literal contains both \' and \", cannot convert for use in lexical grammar.\n\n", grmfid);
						PG::Terminate (6);
					}
				}
				string[i++] = *p++;
			}
		}
		while (*p != 0);
		if (c != '\"')
		{
			string[0] = '\'';
		}
		else
		{
			string[0] = '\"';
			string[i-1] = '\"';
		}
		string[i] = 0;
//	 	printf ("%s\n", string);
		return (string);
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //

char* PG::slash_inside_keyword (char* term_name, char quote)
{
		static char string[128];
		int i = 1;
		char *p;
      if (term_name[0] == '\'') p = term_name+1;
      else                      p = term_name;
		do
		{
			if (*p != '\\')
			{
				string[i++] = *p++;
				if (i > 127)
				{
					n_errors++;
					if (n_errors == 1) prt_log ("\n");
					prt_log ("In file '%s', literal is longer than 128 characters.\n\n", grmfid);
					PG::Terminate (6);
				}
			}
			else
			{
				p++;
				string[i++] = *p++;
			}
		}
		while (*p != 0);
		string[0] =	quote;
      if (string[i-1] == '\'') string[i-1] = quote;
      else                     string[i++] = quote;
		string[i] = 0;
//	 	printf ("%s\n", string);
		return (string);
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //

int   PG::Terminate (int rc)
{
      double dsec;
		int i, min, sec, thou;

      inputt ();

      if (optn[PG_VERBOSE] > 1)
      {
         optncount[MAX_SYM]   = Symtab::n_symbols;
         optncount[MAX_PRO]   = N_prods;
         optncount[MAX_TAIL]  = N_tails;
         optncount[MAX_EBNF]  = 0;
         optncount[MAX_STA]   = org_states;
         optncount[MAX_FIN]   = n_finals;
         optncount[MAX_KER]   = n_kernels;
         optncount[MAX_NTT]   = n_nttran;
         optncount[MAX_TT]    = n_ttran;
         optncount[MAX_TTA]   = n_ttas;
         optncount[MAX_LB]    = n_lookbacks;
         optncount[MAX_LA]    = n_lookah;
         optncount[MAX_INC]   = n_includes;
         optncount[MAX_CH]    = max_child_usage;
         optncount[MAX_ND]    = n_nditems;
			for (i = 0; *MAOption[i].name != 0; i++)
			{
				prt_num (MAOption[i].desc, optncount[MAOption[i].numb], MAOption[i].name, optn[MAOption[i].numb]);
			}
	  	   prt_logonly ("\n");
      }
		PGParser::terminate ();

		char* es = "s";
		char* ws = "s";
		char* cs = "s";
		if (n_errors    == 1) es = "";
		if (n_warnings  == 1) ws = "";
		if (c_states    == 1) cs = "";

      time2 = clock ();
      dsec  = (double)(time2-time1) / CLOCKS_PER_SEC;
      min   = dsec/60;
      sec   = dsec-min*60;
      thou  = (dsec-min*60-sec)*1000;
      int x = memory_max/1024/1024;
      int y = memory_max/1024 - 1024*x;

		prt_log ("%1d min %1d.%03d sec, %d.%03d MB, %d warning%s, %d error%s.\n\n", 
		min, sec, thou, x, y, n_warnings, ws, n_errors, es);

      close_con ();
		close_grm ();
	//	close_log ();
		close_sta ();
		close_lst ();

      if (n_errors > 0) quit (n_errors);
		return 0;
}

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
      
void  PG::PrintGrammar ()
{
      int length, left;
      int h, p, t, L, s, n;
		if (optn[PG_GRAMMAR] == 0)
		{
			option_grammar = 1;
			prt_grm ("\nGRAMMAR LISTING:\n\n");
			prt_grm ("'g' option was not specified.\n");
			return;
		}
}

//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#endif
